package com.md.util;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * 系统的工具类
 * 2021-10-11 18:49
 *
 * @author 刘骄阳
 */
@UtilityClass
@Slf4j
public class SystemUtils {

  /**
   * 生成0-length之间的数字,包含0,不包含length
   *
   * @param length 最大值
   * @return 0-length之间的数字
   */
  public static Integer createRandom(final int length) {
    return RandomUtils.nextInt(0, length);
  }

  /**
   * 生成手机验证码
   *
   * @return 手机验证码
   */
  public static String createSmsCode(final Integer length) {
    return RandomStringUtils.randomAlphanumeric(length).toUpperCase();
  }

  /**
   * 通用重试方法，支持有返回值的任务
   *
   * @param retrySize     最大重试次数
   * @param retryInterval 重试间隔时间
   * @param magnification 重试倍率
   * @param timeUnit      时间单位
   * @param task          任务
   * @param <T>           返回值类型
   * @return 任务执行的返回值
   */
  public static <T> T retryFunction(final Long retrySize,
                                    final Long retryInterval,
                                    final Double magnification,
                                    final TimeUnit timeUnit,
                                    final Callable<T> task) {
    int attempt = 0;
    while (attempt < retrySize) {
      try {
        return task.call();
      } catch (Exception e) {
        try {
          // 计算下次重试的间隔时间，乘以倍率
          long sleepTime = (long) ((attempt * magnification) * retryInterval);
          timeUnit.sleep(sleepTime);
        } catch (Exception sleep) {
          log.error("等待异常: {}", sleep.getMessage(), e);
        }
        attempt++;
        // 如果超过最大重试次数，记录错误并抛出异常
        if (attempt >= retrySize) {
          log.error("任务执行失败，重试次数已用尽: {}", e.getMessage(), e);
        }
      }
    }
    return null;
  }

  /**
   * 通用重试方法，支持无返回值的任务
   *
   * @param retrySize     最大重试次数
   * @param retryInterval 重试间隔时间
   * @param magnification 重试倍率
   * @param timeUnit      时间单位
   * @param task          任务
   */
  public static void retry(final Long retrySize,
                           final Long retryInterval,
                           final Double magnification,
                           final TimeUnit timeUnit,
                           final Runnable task) {
    int attempt = 0;
    while (attempt < retrySize) {
      try {
        // 执行任务
        task.run();
        // 成功则退出
        return;
      } catch (Exception e) {
        try {
          // 计算下次重试的间隔时间，乘以倍率
          long sleepTime = (long) ((attempt * magnification) * retryInterval);
          timeUnit.sleep(sleepTime);
        } catch (Exception sleep) {
          log.error("等待异常: {}", sleep.getMessage(), e);
        }
        attempt++;
        // 如果超过最大重试次数，记录错误并抛出异常
        if (attempt >= retrySize) {
          log.error("任务执行失败，重试次数已用尽: {}", e.getMessage(), e);
        }
      }
    }
  }


  /**
   * 通用重试方法，支持有返回值的任务
   *
   * @param task 任务
   * @param <T>  返回值类型
   * @return 任务执行的返回值
   */
  public static <T> T retryFunction(final Callable<T> task) {
    long defaultRetryInterval = 1;
    double defaultRetryMagnification = 1;
    long defaultMaxRetrySize = 3;
    return retryFunction(defaultMaxRetrySize, defaultRetryInterval, defaultRetryMagnification,
      TimeUnit.SECONDS, task);
  }

  /**
   * 通用重试方法，支持有返回值的任务
   *
   * @param task 任务
   */
  public static void retry(final Runnable task) {
    long defaultRetryInterval = 500;
    double defaultRetryMagnification = 0.5;
    long defaultMaxRetrySize = 3;
    retry(defaultMaxRetrySize, defaultRetryInterval, defaultRetryMagnification,
      TimeUnit.MILLISECONDS, task);
  }
}
